#!/bin/sh

st=0        # exit status (set to 1 if a test fails)
skipped=
fail="**FAIL**"
skip="**SKIP**"
success=" SUCCESS"
# The following check allows this script to know if write of PNG files is
# **not** supported,  This allows more simple skipping of the read/write
# palette index check below.
while read line
do
    # Add specific tests here.  Only 'WRITE' support needs to be checked at
    # present.  Note that there is always a single space between 'define' and
    # 'PNG...'; pnglibconf.h is machine generated.
    case  "$line" in
        "define PNG_WRITE_SUPPORTED") write=1;;
    esac
done <./pnglibconf.h
#
TEST(){
   # Try to make the log file easier to read:
   echo "=============== pngtest $* ===================="
   ./pngtest "$@"
   status=$?
   case "$status" in
       0)  test_status="$success";;
       77) test_status="$skip"
           skipped=1;;
       *)  test_status="$fail"
           st="$status";;
   esac
   echo "===============$test_status $* ===================="
   return "$status"
}

# The "standard" test
TEST --strict "${srcdir}"/pngtest.png

# PNG-3 tests
TEST --strict "${srcdir}"/contrib/testpngs/png-3/*.png

# Various crashers
# Use --relaxed because some come from fuzzers that don't maintain CRCs
TEST --relaxed "${srcdir}"/contrib/testpngs/crashers/badcrc.png
# Use --xfail because there is no reliable way of disabling these errors
# (Adler32 checking cannot be switched off on all builds and there is no
# provision for turning the other checks into warnings.)
TEST --xfail "${srcdir}"/contrib/testpngs/crashers/badadler.png
TEST --xfail "${srcdir}"/contrib/testpngs/crashers/bad_iCCP.png
TEST --xfail "${srcdir}"/contrib/testpngs/crashers/empty_ancillary_chunks.png
for file in "${srcdir}"/contrib/testpngs/crashers/huge_*_chunk.png
do
   TEST --xfail "$file"
done
for file in "${srcdir}"/contrib/testpngs/crashers/huge_*safe_to_copy.png
do
   TEST --xfail "$file"
done
TEST --xfail "${srcdir}"/contrib/testpngs/crashers/huge_IDAT.png

# Regression tests for required warnings (or errors):
check_stdout(){
   # $1: non-empty if this test is supported else an empty string
   # $2: the test file (a bad PNG which must produce a warning, etc)
   # $3: a string which must occur at the end of line on stdout for success
   # result: an error message on descriptor 3 if the string is NOT found
   #
   # WARNING: when this script is executed on MSYS2 (Windows Cygwin variant)
   # pngtest outputs lines terminated with <cr><lf> however the MSYS2 shell
   # expects <lf> (\n) terminated lines so the <cr> ends up in the shell
   # variable 'line' below.  The pattern matching ignores this because of the
   # '*' at the end of the pattern match.
   supported="$1"
   shift
   found=
   skipped=
   while read line
   do
      case "$line" in
         *"$2"*) found=1;;
         *"TEST SKIPPED"*) skipped=1;;
      esac
      echo "$line" # preserve the original output verbatim
   done
   # output the missing warning on descriptor 3:
   test -n "$supported" -a -z "$found" -a -z "$skipped" && echo "$1: $2" >&3
}
# NOTE: traditionally the Bourne shell executed the last element in a pipe
# sequence in the original shell so it could set variables in the original
# shell however this is not reliable and doesn't work in bash.
#
# It *is* reliable to use the actual exit status of the last command in
# the pipeline.
exec 4>&1 # original stdout - the log file
{
   exec 3>&1 # stdout is the pipe at this point
   fail=" FAIL(EXPECTED)" # runtime scope
   success=" SUCCESS(UNEXPECTED)" # there should be a write error
   for file in "${srcdir}"/contrib/testpngs/badpal/*.png
   do
     # The exit code is ignored here, the test is that the particular errors
     # (warnings) are produced.  The original output still ends up in the log
     # file.
     {
        TEST "$file"
        test "$?" -eq 77 && echo "TEST SKIPPED"
     } |
         check_stdout "supported" "$file" \
            'IDAT: Read palette index exceeding num_palette' |
         check_stdout "$write" "$file" \
            'Wrote palette index exceeding num_palette' >&4
   done
   exec 3>&-
} | {
   # This may not be a sub-shell, if it is 'st' is undefined and the exit
   # just ends up as 'exit'.
   while read error
   do
      echo "MISSING REPORT: $error"
      st=1
   done
   exit $st
} || st=$?

test "$st" -gt 0 && exit "$st"
test -n "$skipped" && exit 77
exit 0
